React์ useLayoutEffect ํ ์ ๋ํ ํฌ๊ด์ ์ธ ๊ฐ์ด๋๋ก, ๋๊ธฐ์ ํน์ฑ, ์ฌ์ฉ ์ฌ๋ก, DOM ์ธก์ ๋ฐ ์ ๋ฐ์ดํธ ๊ด๋ฆฌ๋ฅผ ์ํ ๋ชจ๋ฒ ์ฌ๋ก๋ฅผ ์ค๋ช ํฉ๋๋ค.
React useLayoutEffect: ๋๊ธฐ์ DOM ์ธก์ ๋ฐ ์ ๋ฐ์ดํธ
React๋ ์ปดํฌ๋ํธ์ ์ฌ์ด๋ ์ดํํธ(side effect)๋ฅผ ๊ด๋ฆฌํ๊ธฐ ์ํ ๊ฐ๋ ฅํ ํ
(hook)๋ค์ ์ ๊ณตํฉ๋๋ค. ๋๋ถ๋ถ์ ๋น๋๊ธฐ ์ฌ์ด๋ ์ดํํธ๋ useEffect๊ฐ ์ฃผ๋ก ์ฒ๋ฆฌํ์ง๋ง, ๋๊ธฐ์ ์ธ DOM ์ธก์ ๋ฐ ์
๋ฐ์ดํธ๋ฅผ ์ํํด์ผ ํ ๋๋ useLayoutEffect๊ฐ ์ฌ์ฉ๋ฉ๋๋ค. ์ด ๊ฐ์ด๋์์๋ useLayoutEffect์ ๋ชฉ์ , ์ฌ์ฉ ์ฌ๋ก, ๊ทธ๋ฆฌ๊ณ ํจ๊ณผ์ ์ผ๋ก ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ ์ฌ๋ ์๊ฒ ์ดํด๋ด
๋๋ค.
๋๊ธฐ์ DOM ์ ๋ฐ์ดํธ์ ํ์์ฑ ์ดํดํ๊ธฐ
useLayoutEffect์ ์ธ๋ถ ์ฌํญ์ ์ดํด๋ณด๊ธฐ ์ ์, ์ ๋๋๋ก ๋๊ธฐ์ ์ธ DOM ์
๋ฐ์ดํธ๊ฐ ํ์ํ์ง ์ดํดํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค. ๋ธ๋ผ์ฐ์ ๋ ๋๋ง ํ์ดํ๋ผ์ธ์ ๋ค์๊ณผ ๊ฐ์ ์ฌ๋ฌ ๋จ๊ณ๋ก ๊ตฌ์ฑ๋ฉ๋๋ค:
- HTML ํ์ฑ: HTML ๋ฌธ์๋ฅผ DOM ํธ๋ฆฌ๋ก ๋ณํํฉ๋๋ค.
- ๋ ๋๋ง: DOM์ ๊ฐ ์์์ ๋ํ ์คํ์ผ๊ณผ ๋ ์ด์์์ ๊ณ์ฐํฉ๋๋ค.
- ํ์ธํ : ์์๋ค์ ํ๋ฉด์ ๊ทธ๋ฆฝ๋๋ค.
React์ useEffect ํ
์ ๋ธ๋ผ์ฐ์ ๊ฐ ํ๋ฉด์ ๊ทธ๋ฆฐ ํ ๋น๋๊ธฐ์ ์ผ๋ก ์คํ๋ฉ๋๋ค. ์ด๋ ๋ฉ์ธ ์ค๋ ๋๋ฅผ ์ฐจ๋จํ๋ ๊ฒ์ ๋ฐฉ์งํ๊ณ ๋ธ๋ผ์ฐ์ ์ ๋ฐ์์ฑ์ ์ ์งํด์ฃผ๊ธฐ ๋๋ฌธ์ ์ผ๋ฐ์ ์ผ๋ก ์ฑ๋ฅ ๋ฉด์์ ๋ฐ๋์งํฉ๋๋ค. ํ์ง๋ง, ๋ธ๋ผ์ฐ์ ๊ฐ ํ์ธํ
ํ๊ธฐ ์ ์ DOM์ ์ธก์ ํ๊ณ ๊ทธ ์ธก์ ๊ฐ์ ๊ธฐ๋ฐ์ผ๋ก ์ฌ์ฉ์๊ฐ ์ด๊ธฐ ๋ ๋๋ง์ ๋ณด๊ธฐ ์ ์ DOM์ ์
๋ฐ์ดํธํด์ผ ํ๋ ์ํฉ์ด ์์ต๋๋ค. ์๋ฅผ ๋ค๋ฉด ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
- ํดํ ๋ด์ฉ์ ํฌ๊ธฐ์ ์ฌ์ฉ ๊ฐ๋ฅํ ํ๋ฉด ๊ณต๊ฐ์ ๋ฐ๋ผ ํดํ์ ์์น๋ฅผ ์กฐ์ ํ๋ ๊ฒฝ์ฐ.
- ์์๊ฐ ์ปจํ ์ด๋ ์์ ๋ง๋๋ก ๋์ด๋ฅผ ๊ณ์ฐํ๋ ๊ฒฝ์ฐ.
- ์คํฌ๋กค ๋๋ ๋ฆฌ์ฌ์ด์ฆ ์ค์ ์์๋ค์ ์์น๋ฅผ ๋๊ธฐํํ๋ ๊ฒฝ์ฐ.
์ด๋ฌํ ์ ํ์ ์์
์ useEffect๋ฅผ ์ฌ์ฉํ๋ฉด, ๋ธ๋ผ์ฐ์ ๊ฐ useEffect๊ฐ ์คํ๋์ด DOM์ ์
๋ฐ์ดํธํ๊ธฐ ์ ์ ์ด๊ธฐ ์ํ๋ฅผ ๋จผ์ ๊ทธ๋ฆฌ๊ธฐ ๋๋ฌธ์ ์๊ฐ์ ์ธ ๊น๋ฐ์์ด๋ ๊นจ์ง ํ์์ ๊ฒฝํํ ์ ์์ต๋๋ค. ๋ฐ๋ก ์ด๋ด ๋ useLayoutEffect๊ฐ ์ฌ์ฉ๋ฉ๋๋ค.
useLayoutEffect ์๊ฐ
useLayoutEffect๋ useEffect์ ์ ์ฌํ React ํ
์ด์ง๋ง, ๋ธ๋ผ์ฐ์ ๊ฐ ๋ชจ๋ DOM ๋ณ๊ฒฝ์ ์ํํ ํ ํ๋ฉด์ ๊ทธ๋ฆฌ๊ธฐ(paint) ์ ์ ๋๊ธฐ์ ์ผ๋ก ์คํ๋ฉ๋๋ค. ์ด๋ฅผ ํตํด ์๊ฐ์ ์ธ ๊น๋ฐ์ ์์ด DOM ์ธก์ ๊ฐ์ ์ฝ๊ณ DOM์ ์
๋ฐ์ดํธํ ์ ์์ต๋๋ค. ๊ธฐ๋ณธ ๊ตฌ๋ฌธ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
import { useLayoutEffect } from 'react';
function MyComponent() {
useLayoutEffect(() => {
// DOM ๋ณ๊ฒฝ ํ, ํ์ธํธ ์ ์ ์คํํ ์ฝ๋
// ์ ํ์ ์ผ๋ก ํด๋ฆฐ์
ํจ์๋ฅผ ๋ฐํ
return () => {
// ์ปดํฌ๋ํธ๊ฐ ์ธ๋ง์ดํธ๋๊ฑฐ๋ ๋ฆฌ๋ ๋๋ง๋ ๋ ์คํํ ์ฝ๋
};
}, [dependencies]);
return (
{/* ์ปดํฌ๋ํธ ๋ด์ฉ */}
);
}
useEffect์ ๋ง์ฐฌ๊ฐ์ง๋ก useLayoutEffect๋ ๋ ๊ฐ์ ์ธ์๋ฅผ ๋ฐ์ต๋๋ค:
- ์ฌ์ด๋ ์ดํํธ ๋ก์ง์ ํฌํจํ๋ ํจ์.
- ์ ํ์ ์ธ ์์กด์ฑ ๋ฐฐ์ด. ์ดํํธ๋ ์์กด์ฑ ์ค ํ๋๊ฐ ๋ณ๊ฒฝ๋ ๋๋ง ๋ค์ ์คํ๋ฉ๋๋ค. ์์กด์ฑ ๋ฐฐ์ด์ด ๋น์ด ์์ผ๋ฉด(
[]), ์ดํํธ๋ ์ด๊ธฐ ๋ ๋๋ง ํ์ ํ ๋ฒ๋ง ์คํ๋ฉ๋๋ค. ์์กด์ฑ ๋ฐฐ์ด์ด ์ ๊ณต๋์ง ์์ผ๋ฉด, ์ดํํธ๋ ๋ชจ๋ ๋ ๋๋ง ํ์ ์คํ๋ฉ๋๋ค.
์ธ์ useLayoutEffect๋ฅผ ์ฌ์ฉํด์ผ ํ๋๊ฐ
useLayoutEffect๋ฅผ ์ธ์ ์ฌ์ฉํด์ผ ํ๋์ง ์ดํดํ๋ ํต์ฌ์ ๋ธ๋ผ์ฐ์ ๊ฐ ํ์ธํ
ํ๊ธฐ ์ ์ ๋๊ธฐ์ ์ผ๋ก DOM ์ธก์ ๋ฐ ์
๋ฐ์ดํธ๋ฅผ ์ํํด์ผ ํ๋ ์ํฉ์ ํ์
ํ๋ ๊ฒ์
๋๋ค. ์ผ๋ฐ์ ์ธ ์ฌ์ฉ ์ฌ๋ก๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
1. ์์ ํฌ๊ธฐ ์ธก์
๋ค๋ฅธ ์์์ ๋ ์ด์์์ ๊ณ์ฐํ๊ธฐ ์ํด ํน์ ์์์ ๋๋น, ๋์ด ๋๋ ์์น๋ฅผ ์ธก์ ํด์ผ ํ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด, useLayoutEffect๋ฅผ ์ฌ์ฉํ์ฌ ํดํ์ด ํญ์ ๋ทฐํฌํธ ๋ด์ ์์นํ๋๋ก ํ ์ ์์ต๋๋ค.
import React, { useState, useRef, useLayoutEffect } from 'react';
function Tooltip() {
const [isVisible, setIsVisible] = useState(false);
const tooltipRef = useRef(null);
const buttonRef = useRef(null);
useLayoutEffect(() => {
if (isVisible && tooltipRef.current && buttonRef.current) {
const buttonRect = buttonRef.current.getBoundingClientRect();
const tooltipWidth = tooltipRef.current.offsetWidth;
const windowWidth = window.innerWidth;
// ํดํ์ ์ด์์ ์ธ ์์น ๊ณ์ฐ
let left = buttonRect.left + (buttonRect.width / 2) - (tooltipWidth / 2);
// ํดํ์ด ๋ทฐํฌํธ๋ฅผ ๋ฒ์ด๋ ๊ฒฝ์ฐ ์์น ์กฐ์
if (left < 0) {
left = 10; // ์ผ์ชฝ ๊ฐ์ฅ์๋ฆฌ๋ก๋ถํฐ ์ต์ ์ฌ๋ฐฑ
} else if (left + tooltipWidth > windowWidth) {
left = windowWidth - tooltipWidth - 10; // ์ค๋ฅธ์ชฝ ๊ฐ์ฅ์๋ฆฌ๋ก๋ถํฐ ์ต์ ์ฌ๋ฐฑ
}
tooltipRef.current.style.left = `${left}px`;
tooltipRef.current.style.top = `${buttonRect.bottom + 5}px`;
}
}, [isVisible]);
return (
{isVisible && (
์ด๊ฒ์ ํดํ ๋ฉ์์ง์
๋๋ค.
)}
);
}
์ด ์์ ์์๋ useLayoutEffect๋ฅผ ์ฌ์ฉํ์ฌ ๋ฒํผ์ ์์น์ ๋ทฐํฌํธ ํฌ๊ธฐ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํดํ์ ์์น๋ฅผ ๊ณ์ฐํฉ๋๋ค. ์ด๋ฅผ ํตํด ํดํ์ด ํญ์ ๋ณด์ด๋๋ก ํ๊ณ ํ๋ฉด์ ๋ฒ์ด๋์ง ์๋๋ก ๋ณด์ฅํฉ๋๋ค. getBoundingClientRect ๋ฉ์๋๋ ๋ทฐํฌํธ๋ฅผ ๊ธฐ์ค์ผ๋ก ๋ฒํผ์ ํฌ๊ธฐ์ ์์น๋ฅผ ๊ฐ์ ธ์ค๋ ๋ฐ ์ฌ์ฉ๋ฉ๋๋ค.
2. ์์ ์์น ๋๊ธฐํ
์ฌ์ฉ์๊ฐ ์คํฌ๋กคํ ๋ ๋ฐ๋ผ์ค๋ ์คํฐํค ํค๋(sticky header)์ ๊ฐ์ด ํ ์์์ ์์น๋ฅผ ๋ค๋ฅธ ์์์ ๋๊ธฐํํด์ผ ํ ์ ์์ต๋๋ค. ์ด ๊ฒฝ์ฐ์๋ useLayoutEffect๋ฅผ ์ฌ์ฉํ๋ฉด ๋ธ๋ผ์ฐ์ ๊ฐ ํ์ธํ
ํ๊ธฐ ์ ์ ์์๋ค์ด ์ฌ๋ฐ๋ฅด๊ฒ ์ ๋ ฌ๋๋๋ก ํ์ฌ ์๊ฐ์ ๊ฒฐํจ์ ํผํ ์ ์์ต๋๋ค.
import React, { useState, useRef, useLayoutEffect } from 'react';
function StickyHeader() {
const [isSticky, setIsSticky] = useState(false);
const headerRef = useRef(null);
const placeholderRef = useRef(null);
useLayoutEffect(() => {
const handleScroll = () => {
if (headerRef.current && placeholderRef.current) {
const headerHeight = headerRef.current.offsetHeight;
const headerTop = headerRef.current.offsetTop;
const scrollPosition = window.pageYOffset;
if (scrollPosition > headerTop) {
setIsSticky(true);
placeholderRef.current.style.height = `${headerHeight}px`;
} else {
setIsSticky(false);
placeholderRef.current.style.height = '0px';
}
}
};
window.addEventListener('scroll', handleScroll);
return () => {
window.removeEventListener('scroll', handleScroll);
};
}, []);
return (
์คํฐํค ํค๋
{/* ์คํฌ๋กคํ ์ผ๋ถ ์ฝํ
์ธ */}
);
}
์ด ์์ ๋ ์ฌ์ฉ์๊ฐ ์คํฌ๋กคํ ๋ ๋ทฐํฌํธ ์๋จ์ ๊ณ ์ ๋๋ ์คํฐํค ํค๋๋ฅผ ๋ง๋๋ ๋ฐฉ๋ฒ์ ๋ณด์ฌ์ค๋๋ค. useLayoutEffect๋ ํค๋์ ๋์ด๋ฅผ ๊ณ์ฐํ๊ณ ํ๋ ์ด์คํ๋ ์์์ ๋์ด๋ฅผ ์ค์ ํ์ฌ ํค๋๊ฐ ๊ณ ์ ๋ ๋ ์ฝํ
์ธ ๊ฐ ์๋ก ์ ํํ๋ ๊ฒ์ ๋ฐฉ์งํ๋ ๋ฐ ์ฌ์ฉ๋ฉ๋๋ค. offsetTop ์์ฑ์ ๋ฌธ์์ ๋ํ ํค๋์ ์ด๊ธฐ ์์น๋ฅผ ๊ฒฐ์ ํ๋ ๋ฐ ์ฌ์ฉ๋ฉ๋๋ค.
3. ํฐํธ ๋ก๋ฉ ์ค ํ ์คํธ ์ ํ ๋ฐฉ์ง
์น ํฐํธ๊ฐ ๋ก๋ฉ๋ ๋ ๋ธ๋ผ์ฐ์ ๋ ์ด๊ธฐ์ ๋์ฒด ํฐํธ(fallback font)๋ฅผ ํ์ํ ์ ์์ผ๋ฉฐ, ์ด๋ก ์ธํด ์ปค์คํ
ํฐํธ๊ฐ ๋ก๋๋๋ฉด ํ
์คํธ๊ฐ ์ฌ๋ฐฐ์น(reflow)๋ ์ ์์ต๋๋ค. useLayoutEffect๋ฅผ ์ฌ์ฉํ๋ฉด ๋์ฒด ํฐํธ๋ก ๋ ๋๋ง๋ ํ
์คํธ์ ๋์ด๋ฅผ ๊ณ์ฐํ๊ณ ์ปจํ
์ด๋์ ์ต์ ๋์ด๋ฅผ ์ค์ ํ์ฌ ์ด๋ฌํ ์ ํ ํ์์ ๋ฐฉ์งํ ์ ์์ต๋๋ค.
import React, { useRef, useLayoutEffect, useState } from 'react';
function FontLoadingComponent() {
const textRef = useRef(null);
const [minHeight, setMinHeight] = useState(0);
useLayoutEffect(() => {
if (textRef.current) {
// ๋์ฒด ํฐํธ๋ก ๋์ด ์ธก์
const height = textRef.current.offsetHeight;
setMinHeight(height);
}
}, []);
return (
์ด๊ฒ์ ์ปค์คํ
ํฐํธ๋ฅผ ์ฌ์ฉํ๋ ํ
์คํธ์
๋๋ค.
);
}
์ด ์์ ์์ useLayoutEffect๋ ๋์ฒด ํฐํธ๋ฅผ ์ฌ์ฉํ์ฌ ๋ฌธ๋จ ์์์ ๋์ด๋ฅผ ์ธก์ ํฉ๋๋ค. ๊ทธ๋ฐ ๋ค์ ๋ถ๋ชจ div์ minHeight ์คํ์ผ ์์ฑ์ ์ค์ ํ์ฌ ์ปค์คํ
ํฐํธ๊ฐ ๋ก๋๋ ๋ ํ
์คํธ๊ฐ ์ ํํ๋ ๊ฒ์ ๋ฐฉ์งํฉ๋๋ค. "MyCustomFont"๋ฅผ ์ค์ ์ปค์คํ
ํฐํธ ์ด๋ฆ์ผ๋ก ๋ฐ๊พธ์ธ์.
useLayoutEffect vs. useEffect: ์ฃผ์ ์ฐจ์ด์
useLayoutEffect์ useEffect์ ๊ฐ์ฅ ์ค์ํ ์ฐจ์ด์ ์ ์คํ ์์ ์
๋๋ค:
useLayoutEffect: DOM ๋ณ๊ฒฝ ํ, ๋ธ๋ผ์ฐ์ ๊ฐ ํ์ธํ ํ๊ธฐ ์ ์ ๋๊ธฐ์ ์ผ๋ก ์คํ๋ฉ๋๋ค. ์ด๋ ์ดํํธ ์คํ์ด ๋๋ ๋๊น์ง ๋ธ๋ผ์ฐ์ ์ ํ์ธํ ์ ์ฐจ๋จํฉ๋๋ค.useEffect: ๋ธ๋ผ์ฐ์ ๊ฐ ํ๋ฉด์ ๊ทธ๋ฆฐ ํ ๋น๋๊ธฐ์ ์ผ๋ก ์คํ๋ฉ๋๋ค. ์ด๋ ๋ธ๋ผ์ฐ์ ์ ํ์ธํ ์ ์ฐจ๋จํ์ง ์์ต๋๋ค.
useLayoutEffect๋ ๋ธ๋ผ์ฐ์ ์ ํ์ธํ
์ ์ฐจ๋จํ๋ฏ๋ก ๋๋ฌผ๊ฒ ์ฌ์ฉํด์ผ ํฉ๋๋ค. useLayoutEffect๋ฅผ ๋จ์ฉํ๋ฉด, ํนํ ์ดํํธ์ ๋ณต์กํ๊ฑฐ๋ ์๊ฐ์ด ๋ง์ด ๊ฑธ๋ฆฌ๋ ๊ณ์ฐ์ด ํฌํจ๋ ๊ฒฝ์ฐ ์ฑ๋ฅ ๋ฌธ์ ๋ฅผ ์ ๋ฐํ ์ ์์ต๋๋ค.
์ฃผ์ ์ฐจ์ด์ ์ ์์ฝํ ํ๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
| ๊ธฐ๋ฅ | useLayoutEffect |
useEffect |
|---|---|---|
| ์คํ ์์ | ๋๊ธฐ์ (ํ์ธํธ ์ ) | ๋น๋๊ธฐ์ (ํ์ธํธ ํ) |
| ์ฐจ๋จ ์ฌ๋ถ | ๋ธ๋ผ์ฐ์ ํ์ธํ ์ฐจ๋จ | ์ฐจ๋จ ์ ํจ |
| ์ฌ์ฉ ์ฌ๋ก | ๋๊ธฐ์ ์คํ์ด ํ์ํ DOM ์ธก์ ๋ฐ ์ ๋ฐ์ดํธ | ๋๋ถ๋ถ์ ๋ค๋ฅธ ์ฌ์ด๋ ์ดํํธ (API ํธ์ถ, ํ์ด๋จธ ๋ฑ) |
| ์ฑ๋ฅ ์ํฅ | ์ ์ฌ์ ์ผ๋ก ๋ ๋์ (์ฐจ๋จ์ผ๋ก ์ธํด) | ๋ ๋ฎ์ |
useLayoutEffect ์ฌ์ฉ์ ์ํ ๋ชจ๋ฒ ์ฌ๋ก
useLayoutEffect๋ฅผ ํจ๊ณผ์ ์ผ๋ก ์ฌ์ฉํ๊ณ ์ฑ๋ฅ ๋ฌธ์ ๋ฅผ ํผํ๋ ค๋ฉด ๋ค์ ๋ชจ๋ฒ ์ฌ๋ก๋ฅผ ๋ฐ๋ฅด์ธ์:
1. ๋๋ฌผ๊ฒ ์ฌ์ฉํ๊ธฐ
๋๊ธฐ์ ์ธ DOM ์ธก์ ๋ฐ ์
๋ฐ์ดํธ๊ฐ ๋ฐ๋์ ํ์ํ ๊ฒฝ์ฐ์๋ง useLayoutEffect๋ฅผ ์ฌ์ฉํ์ธ์. ๋๋ถ๋ถ์ ๋ค๋ฅธ ์ฌ์ด๋ ์ดํํธ์๋ useEffect๊ฐ ๋ ๋์ ์ ํ์
๋๋ค.
2. ์ดํํธ ํจ์๋ฅผ ์งง๊ณ ํจ์จ์ ์ผ๋ก ์ ์งํ๊ธฐ
useLayoutEffect์ ์ดํํธ ํจ์๋ ์ฐจ๋จ ์๊ฐ์ ์ต์ํํ๊ธฐ ์ํด ๊ฐ๋ฅํ ํ ์งง๊ณ ํจ์จ์ ์ด์ด์ผ ํฉ๋๋ค. ์ดํํธ ํจ์ ๋ด์์ ๋ณต์กํ ๊ณ์ฐ์ด๋ ์๊ฐ์ด ๋ง์ด ๊ฑธ๋ฆฌ๋ ์์
์ ํผํ์ธ์.
3. ์์กด์ฑ์ ํ๋ช ํ๊ฒ ์ฌ์ฉํ๊ธฐ
ํญ์ useLayoutEffect์ ์์กด์ฑ ๋ฐฐ์ด์ ์ ๊ณตํ์ธ์. ์ด๋ ๊ฒ ํ๋ฉด ์ดํํธ๊ฐ ํ์ํ ๋๋ง ๋ค์ ์คํ๋ฉ๋๋ค. ์์กด์ฑ ๋ฐฐ์ด์ ์ด๋ค ๋ณ์๋ฅผ ํฌํจํด์ผ ํ ์ง ์ ์คํ๊ฒ ๊ณ ๋ คํ์ธ์. ๋ถํ์ํ ์์กด์ฑ์ ํฌํจํ๋ฉด ๋ถํ์ํ ๋ฆฌ๋ ๋๋ง๊ณผ ์ฑ๋ฅ ๋ฌธ์ ๋ฅผ ์ ๋ฐํ ์ ์์ต๋๋ค.
4. ๋ฌดํ ๋ฃจํ ํผํ๊ธฐ
useLayoutEffect ๋ด์์ ์ดํํธ์ ์์กด์ฑ์ด๊ธฐ๋ ํ ์ํ ๋ณ์๋ฅผ ์
๋ฐ์ดํธํ์ฌ ๋ฌดํ ๋ฃจํ๋ฅผ ๋ง๋ค์ง ์๋๋ก ์ฃผ์ํ์ธ์. ์ด๋ ์ดํํธ๊ฐ ๋ฐ๋ณต์ ์ผ๋ก ๋ค์ ์คํ๋์ด ๋ธ๋ผ์ฐ์ ๊ฐ ๋ฉ์ถ๋ ์์ธ์ด ๋ ์ ์์ต๋๋ค. DOM ์ธก์ ๊ฐ์ ๊ธฐ๋ฐ์ผ๋ก ์ํ ๋ณ์๋ฅผ ์
๋ฐ์ดํธํด์ผ ํ๋ ๊ฒฝ์ฐ, ref๋ฅผ ์ฌ์ฉํ์ฌ ์ธก์ ๋ ๊ฐ์ ์ ์ฅํ๊ณ ์ํ๋ฅผ ์
๋ฐ์ดํธํ๊ธฐ ์ ์ ์ด์ ๊ฐ๊ณผ ๋น๊ตํ๋ ๊ฒ์ ๊ณ ๋ คํ์ธ์.
5. ๋์ ๊ณ ๋ คํ๊ธฐ
useLayoutEffect๋ฅผ ์ฌ์ฉํ๊ธฐ ์ ์ ๋๊ธฐ์ ์ธ DOM ์
๋ฐ์ดํธ๊ฐ ํ์ ์๋ ๋์์ ์ธ ํด๊ฒฐ์ฑ
์ด ์๋์ง ๊ณ ๋ คํด ๋ณด์ธ์. ์๋ฅผ ๋ค์ด, ์๋ฐ์คํฌ๋ฆฝํธ ๊ฐ์
์์ด CSS๋ฅผ ์ฌ์ฉํ์ฌ ์ํ๋ ๋ ์ด์์์ ๋ฌ์ฑํ ์ ์์ต๋๋ค. CSS ํธ๋์ง์
๋ฐ ์ ๋๋ฉ์ด์
๋ํ useLayoutEffect ์์ด ๋ถ๋๋ฌ์ด ์๊ฐ ํจ๊ณผ๋ฅผ ์ ๊ณตํ ์ ์์ต๋๋ค.
useLayoutEffect์ ์๋ฒ ์ฌ์ด๋ ๋ ๋๋ง(SSR)
useLayoutEffect๋ ๋ธ๋ผ์ฐ์ ์ DOM์ ์์กดํ๋ฏ๋ก ์๋ฒ ์ฌ์ด๋ ๋ ๋๋ง(SSR) ์ค์ ์ฌ์ฉํ๋ฉด ๊ฒฝ๊ณ ๊ฐ ๋ฐ์ํฉ๋๋ค. ์ด๋ ์๋ฒ์๋ DOM์ด ์๊ธฐ ๋๋ฌธ์
๋๋ค. ์ด ๊ฒฝ๊ณ ๋ฅผ ํผํ๋ ค๋ฉด ์กฐ๊ฑด๋ถ ๊ฒ์ฌ๋ฅผ ์ฌ์ฉํ์ฌ useLayoutEffect๊ฐ ํด๋ผ์ด์ธํธ ์ธก์์๋ง ์คํ๋๋๋ก ํ ์ ์์ต๋๋ค.
import React, { useLayoutEffect, useEffect, useState } from 'react';
function MyComponent() {
const [isClient, setIsClient] = useState(false);
useEffect(() => {
setIsClient(true);
}, []);
useLayoutEffect(() => {
if (isClient) {
// DOM์ ์์กดํ๋ ์ฝ๋
console.log('useLayoutEffect๊ฐ ํด๋ผ์ด์ธํธ์์ ์คํ ์ค');
}
}, [isClient]);
return (
{/* ์ปดํฌ๋ํธ ๋ด์ฉ */}
);
}
์ด ์์ ์์๋ useEffect ํ
์ ์ฌ์ฉํ์ฌ ์ปดํฌ๋ํธ๊ฐ ํด๋ผ์ด์ธํธ ์ธก์ ๋ง์ดํธ๋ ํ isClient ์ํ ๋ณ์๋ฅผ true๋ก ์ค์ ํฉ๋๋ค. ๊ทธ๋ฌ๋ฉด useLayoutEffect ํ
์ isClient๊ฐ true์ผ ๋๋ง ์คํ๋์ด ์๋ฒ์์ ์คํ๋๋ ๊ฒ์ ๋ฐฉ์งํฉ๋๋ค.
๋ ๋ค๋ฅธ ์ ๊ทผ ๋ฐฉ์์ SSR ์ค์๋ useEffect๋ก ๋์ฒด๋๋ ์ปค์คํ
ํ
์ ์ฌ์ฉํ๋ ๊ฒ์
๋๋ค:
import { useLayoutEffect, useEffect } from 'react';
const useIsomorphicLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect;
export default useIsomorphicLayoutEffect;
๊ทธ๋ฐ ๋ค์, useLayoutEffect๋ useEffect๋ฅผ ์ง์ ์ฌ์ฉํ๋ ๋์ useIsomorphicLayoutEffect๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค. ์ด ์ปค์คํ
ํ
์ ์ฝ๋๊ฐ ๋ธ๋ผ์ฐ์ ํ๊ฒฝ(์ฆ, typeof window !== 'undefined')์์ ์คํ ์ค์ธ์ง ํ์ธํฉ๋๋ค. ๋ง์ฝ ๊ทธ๋ ๋ค๋ฉด useLayoutEffect๋ฅผ ์ฌ์ฉํ๊ณ , ๊ทธ๋ ์ง ์๋ค๋ฉด useEffect๋ฅผ ์ฌ์ฉํฉ๋๋ค. ์ด๋ ๊ฒ ํ๋ฉด SSR ์ค ๊ฒฝ๊ณ ๋ฅผ ํผํ๋ฉด์๋ ํด๋ผ์ด์ธํธ ์ธก์์๋ useLayoutEffect์ ๋๊ธฐ์ ๋์์ ํ์ฉํ ์ ์์ต๋๋ค.
์ ์ญ์ ๊ณ ๋ ค์ฌํญ ๋ฐ ์์
์ ์ธ๊ณ ์ฌ์ฉ์๋ฅผ ๋์์ผ๋ก ํ๋ ์ ํ๋ฆฌ์ผ์ด์
์์ useLayoutEffect๋ฅผ ์ฌ์ฉํ ๋ ๋ค์ ์ฌํญ์ ๊ณ ๋ คํด์ผ ํฉ๋๋ค:
- ๋ค์ํ ํฐํธ ๋ ๋๋ง: ํฐํธ ๋ ๋๋ง์ ์ด์ ์ฒด์ ์ ๋ธ๋ผ์ฐ์ ๋ง๋ค ๋ค๋ฅผ ์ ์์ต๋๋ค. ๋ ์ด์์ ์กฐ์ ์ด ์ฌ๋ฌ ํ๋ซํผ์์ ์ผ๊ด๋๊ฒ ์๋ํ๋์ง ํ์ธํ์ธ์. ๋ค์ํ ๊ธฐ๊ธฐ์ ์ด์ ์ฒด์ ์์ ์ ํ๋ฆฌ์ผ์ด์ ์ ํ ์คํธํ์ฌ ๋ถ์ผ์น ์ฌํญ์ ์ฐพ์ ํด๊ฒฐํ๋ ๊ฒ์ ๊ณ ๋ คํ์ธ์.
- ์ค๋ฅธ์ชฝ์์ ์ผ์ชฝ์ผ๋ก ์ฐ๋(RTL) ์ธ์ด: ์ ํ๋ฆฌ์ผ์ด์
์ด RTL ์ธ์ด(์: ์๋์ด, ํ๋ธ๋ฆฌ์ด)๋ฅผ ์ง์ํ๋ ๊ฒฝ์ฐ, DOM ์ธก์ ๋ฐ ์
๋ฐ์ดํธ๊ฐ RTL ๋ชจ๋์ ๋ ์ด์์์ ์ด๋ค ์ํฅ์ ๋ฏธ์น๋์ง ์ ์ํด์ผ ํฉ๋๋ค. ๋ฌผ๋ฆฌ์ ์์ฑ(์:
margin-left,margin-right) ๋์ CSS ๋ ผ๋ฆฌ์ ์์ฑ(์:margin-inline-start,margin-inline-end)์ ์ฌ์ฉํ์ฌ ์ ์ ํ ๋ ์ด์์ ์ ์์ ๋ณด์ฅํ์ธ์. - ๊ตญ์ ํ(i18n): ํ ์คํธ ๊ธธ์ด๋ ์ธ์ด๋ง๋ค ํฌ๊ฒ ๋ค๋ฅผ ์ ์์ต๋๋ค. ํ ์คํธ ๋ด์ฉ์ ๊ธฐ๋ฐ์ผ๋ก ๋ ์ด์์์ ์กฐ์ ํ ๋ ๋ค๋ฅธ ์ธ์ด์์ ๋ ๊ธธ๊ฑฐ๋ ์งง์ ํ ์คํธ ๋ฌธ์์ด์ ๊ฐ๋ฅ์ฑ์ ๊ณ ๋ คํ์ธ์. ์ ์ฐํ ๋ ์ด์์ ๊ธฐ์ (์: CSS flexbox, grid)์ ์ฌ์ฉํ์ฌ ๋ค์ํ ํ ์คํธ ๊ธธ์ด๋ฅผ ์์ฉํ์ธ์.
- ์ ๊ทผ์ฑ(a11y): ๋ ์ด์์ ์กฐ์ ์ด ์ ๊ทผ์ฑ์ ๋ถ์ ์ ์ธ ์ํฅ์ ๋ฏธ์น์ง ์๋๋ก ํ์ธ์. ์๋ฐ์คํฌ๋ฆฝํธ๊ฐ ๋นํ์ฑํ๋์๊ฑฐ๋ ์ฌ์ฉ์๊ฐ ๋ณด์กฐ ๊ธฐ์ ์ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ ์ฝํ ์ธ ์ ์ ๊ทผํ ์ ์๋ ๋์ฒด ๋ฐฉ๋ฒ์ ์ ๊ณตํ์ธ์. ARIA ์์ฑ์ ์ฌ์ฉํ์ฌ ๋ ์ด์์ ์กฐ์ ์ ๊ตฌ์กฐ์ ๋ชฉ์ ์ ๋ํ ์๋ฏธ๋ก ์ ์ ๋ณด๋ฅผ ์ ๊ณตํ์ธ์.
์์: ๋ค๊ตญ์ด ํ๊ฒฝ์์์ ๋์ ์ฝํ ์ธ ๋ก๋ฉ ๋ฐ ๋ ์ด์์ ์กฐ์
๋ค์ํ ์ธ์ด๋ก ๊ธฐ์ฌ๋ฅผ ๋์ ์ผ๋ก ๋ก๋ํ๋ ๋ด์ค ์น์ฌ์ดํธ๋ฅผ ์์ํด ๋ณด์ธ์. ๊ฐ ๊ธฐ์ฌ์ ๋ ์ด์์์ ์ฝํ
์ธ ์ ๊ธธ์ด์ ์ฌ์ฉ์๊ฐ ์ ํธํ๋ ํฐํธ ์ค์ ์ ๋ฐ๋ผ ์กฐ์ ๋์ด์ผ ํฉ๋๋ค. ์ด ์๋๋ฆฌ์ค์์ useLayoutEffect๋ฅผ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
- ๊ธฐ์ฌ ๋ด์ฉ ์ธก์ : ๊ธฐ์ฌ ๋ด์ฉ์ด ๋ก๋๋๊ณ ๋ ๋๋ง๋ ํ(๊ทธ๋ฌ๋ ํ์๋๊ธฐ ์ )
useLayoutEffect๋ฅผ ์ฌ์ฉํ์ฌ ๊ธฐ์ฌ ์ปจํ ์ด๋์ ๋์ด๋ฅผ ์ธก์ ํฉ๋๋ค. - ์ฌ์ฉ ๊ฐ๋ฅํ ๊ณต๊ฐ ๊ณ์ฐ: ํค๋, ํธํฐ ๋ฐ ๊ธฐํ UI ์์๋ฅผ ๊ณ ๋ คํ์ฌ ํ๋ฉด์์ ๊ธฐ์ฌ์ ์ฌ์ฉํ ์ ์๋ ๊ณต๊ฐ์ ๊ฒฐ์ ํฉ๋๋ค.
- ๋ ์ด์์ ์กฐ์ : ๊ธฐ์ฌ์ ๋์ด์ ์ฌ์ฉ ๊ฐ๋ฅํ ๊ณต๊ฐ์ ๊ธฐ๋ฐ์ผ๋ก ์ต์ ์ ๊ฐ๋ ์ฑ์ ๋ณด์ฅํ๋๋ก ๋ ์ด์์์ ์กฐ์ ํฉ๋๋ค. ์๋ฅผ ๋ค์ด, ํฐํธ ํฌ๊ธฐ, ์ค ๊ฐ๊ฒฉ ๋๋ ์ด ๋๋น๋ฅผ ์กฐ์ ํ ์ ์์ต๋๋ค.
- ์ธ์ด๋ณ ์กฐ์ ์ ์ฉ: ๊ธฐ์ฌ๊ฐ ๋ ๊ธด ํ ์คํธ ๋ฌธ์์ด์ ๊ฐ์ง ์ธ์ด์ธ ๊ฒฝ์ฐ, ์ฆ๊ฐ๋ ํ ์คํธ ๊ธธ์ด๋ฅผ ์์ฉํ๊ธฐ ์ํด ์ถ๊ฐ์ ์ธ ์กฐ์ ์ด ํ์ํ ์ ์์ต๋๋ค.
์ด ์๋๋ฆฌ์ค์์ useLayoutEffect๋ฅผ ์ฌ์ฉํ๋ฉด ์ฌ์ฉ์๊ฐ ๋ณด๊ธฐ ์ ์ ๊ธฐ์ฌ ๋ ์ด์์์ด ์ฌ๋ฐ๋ฅด๊ฒ ์กฐ์ ๋๋๋ก ๋ณด์ฅํ์ฌ ์๊ฐ์ ๊ฒฐํจ์ ๋ฐฉ์งํ๊ณ ๋ ๋์ ์ฝ๊ธฐ ๊ฒฝํ์ ์ ๊ณตํ ์ ์์ต๋๋ค.
๊ฒฐ๋ก
useLayoutEffect๋ React์์ ๋๊ธฐ์ ์ธ DOM ์ธก์ ๋ฐ ์
๋ฐ์ดํธ๋ฅผ ์ํํ๊ธฐ ์ํ ๊ฐ๋ ฅํ ํ
์
๋๋ค. ๊ทธ๋ฌ๋ ์ ์ฌ์ ์ธ ์ฑ๋ฅ ์ํฅ ๋๋ฌธ์ ์ ์คํ๊ฒ ์ฌ์ฉํด์ผ ํฉ๋๋ค. useLayoutEffect์ useEffect์ ์ฐจ์ด์ ์ ์ดํดํ๊ณ , ๋ชจ๋ฒ ์ฌ๋ก๋ฅผ ๋ฐ๋ฅด๋ฉฐ, ์ ์ญ์ ์ธ ์ํฅ์ ๊ณ ๋ คํจ์ผ๋ก์จ useLayoutEffect๋ฅผ ํ์ฉํ์ฌ ๋ถ๋๋ฝ๊ณ ์๊ฐ์ ์ผ๋ก ๋งค๋ ฅ์ ์ธ ์ฌ์ฉ์ ์ธํฐํ์ด์ค๋ฅผ ๋ง๋ค ์ ์์ต๋๋ค.
useLayoutEffect๋ฅผ ์ฌ์ฉํ ๋๋ ์ฑ๋ฅ๊ณผ ์ ๊ทผ์ฑ์ ์ฐ์ ์ํด์ผ ํฉ๋๋ค. ํญ์ ๋๊ธฐ์ ์ธ DOM ์
๋ฐ์ดํธ๊ฐ ํ์ ์๋ ๋์์ ์ธ ํด๊ฒฐ์ฑ
์ ๊ณ ๋ คํ๊ณ , ์ ์ธ๊ณ ์ฌ์ฉ์์๊ฒ ์ผ๊ด๋๊ณ ์ฆ๊ฑฐ์ด ์ฌ์ฉ์ ๊ฒฝํ์ ๋ณด์ฅํ๊ธฐ ์ํด ๋ค์ํ ๊ธฐ๊ธฐ์ ๋ธ๋ผ์ฐ์ ์์ ์ ํ๋ฆฌ์ผ์ด์
์ ์ฒ ์ ํ ํ
์คํธํ์ธ์.